#include "Frame.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <errno.h>
static bool interrupt=false;

void System_interface(char *ref, std::string c, int n_bytes)
{
    FILE *in;
    char *command=new char[c.size()+1];
    command[c.size()]=0;
    memcpy(command,c.c_str(),c.size());
    in = popen(command ,"r");
    fgets(ref,n_bytes,in);
    pclose(in);
    delete[] command, in;
}

void Concact(Message_queue &mq, std::string &buff){
    std::ostringstream msg;
    
    msg << inet_ntoa(mq.cli_addr.sin_addr);
    msg << ";";
    msg << int(mq.package.header.version);
    msg << ";";
    msg << int(mq.package.header.domain);
    msg << ";";
    msg << int(mq.package.header.type_message);
    msg << ";";
    msg << mq.package.header.n_register;
    msg << ";";
    msg << mq.package.header.id_server_source;
    msg << ";";
    msg << mq.package.header.id_server_destination;
    msg << ";";
    msg << int(mq.package.header.flag);
    msg << ";";
    msg << mq.package.header.offset;
    msg << ";";
    msg << mq.package.f_time;
    msg << ";";
    msg << inet_ntoa(mq.package.id_client.sin_addr);
    msg <<"::";
    msg << ntohs(mq.package.id_client.sin_port);
    msg << ";";
    msg << mq.package.sequence_number;
    msg << ";";
    msg << mq.package.acknowledge_number;
    msg << ";";
    msg << mq.package.next_sequence_number;
    msg << ";";
    msg << mq.package.id_server_guardian;
    msg << ";";
    msg << inet_ntoa(mq.package.ip_server_guardian.sin_addr);
    buff+=msg.str();
} 


void Loge (std::ofstream &file,const int &id, std::string &buffer, int &entry){
    
    char time[25];
    buffer="";
    std::ostringstream ss;
    ss << entry;
    ss << ";";
    ss << id;
    buffer+=ss.str();
    buffer+=";";
    
    switch(id){ 
        case LOG_QUEUE_ERR_LOG:{
            
            buffer+="Error, el programa ha fallado al crear la cola de mensajes para el (Logger),"
                    "verifique si se ha ejecutado con privilegios de root;";
            break;
        }
        case LOG_QUEUE_ERR_UNPACKER:{
            buffer+="Error, el programa ha fallado al crear la cola de mensajes para el (Desempacador),"
                    "verifique si se ha ejecutado con privilegios de root;";
            break;
        }
        case LOG_QUEUE_EVNT_UNPACKER:{
            buffer+="El (Desempacador) ha iniciado correctamente;";
            break;
        }
        case LOG_QUEUE_ERR_IN_UNPACKER:{
            buffer+="Error de lectura en el (Desempacador), verifique conectividad y puertos;";
            break;
        }
        case LOG_QUEUE_EVNT_IN_INVESTMENT:{
            buffer+="Se ha recibido un mensaje de (Investidura);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_GC:{
            buffer+="Se ha recibido una confirmación de un mensaje de (Guarda);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_MC:{
            buffer+="Se ha recibido una confirmación de un mensaje de (Desaparecido);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_ADOPTIONP:{
            buffer+="Se ha recibido un mensaje de (Adopción);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_BOOKMARK:{
            buffer+="Se ha recibido un mensaje de (Marcador);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_UNKNOWN:{
            buffer+="Error,Se ha recibido un mensaje no identificado y/o admisible por el protocolo;";
            break;
        }
        case LOG_QUEUE_EVNT_GUARD:{
            buffer+="Se ha identificado una sesión extraviada;";
            break;
        }
        case LOG_QUEUE_EVNT_MISSING:{
            buffer+="Se ha identificado una sesión perdida;";
            break;
        }
        case LOG_QUEUE_EVNT_IN_MEMBERSHIP:{
            buffer+="Se ha recibido un mensaje de (Membresía);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_GUARD_REPORT:{
            buffer+="Se ha recibido un mensaje de (Reporte de guarda);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_MISSING_REPORT:{
            buffer+="Se ha recibido un mensaje de (Reporte de desaparicido);";
            break;
        }
        case LOG_QUEUE_EVNT_IN_INVESTMENT_C:{
            buffer+="Se ha recibido una confirmación de un mensaje de (Investidura);";
            break;
        }
        case LOG_QUEUE_ERR_UNPACKER_QCP:{
            buffer+="Error, el programa ha fallado al crear la cola de mensajes para "
                    "el (El cliente del protocolo), verifique si se ha ejecutado con privilegios de root;";
            break;
        }
        case LOG_QUEUE_EVNT_OUT_MEMBERSHIP:{
            buffer+="Se ha enviado un mensaje de (Membresía);";
            break;
        }
        
        case LOG_QUEUE_ENVT_CONNECT:{
            buffer+="Se ha iniciado el proceso (Keepandtouch), Conexión exitosa!;";
            break;
        }
        
        case LOG_QUEUE_ERR_TIMEOUT:{
            buffer+="Error, se ha perdido la conexión debido a la expiración del tiempo de respuesta;";
            break;
        }
      
        case LOG_QUEUE_ERR_OUT_SEND:{
            buffer+="Error de escritura en el socket, verifique conectividad;";
            break;
        }
        
        case LOG_QUEUE_ERR_TOUCH:{
            buffer+="Error, se ha perdido la conexión debido a que ha fallado el inicio del proceso"
                    "(Keepandtouch);";
            break;
        }
        
        case LOG_QUEUE_ERR_POOL:{
            buffer+="Error, el pool de indentificaciones de quimera ha llegado a su límite;";
            break;
        }
        case LOG_QUEUE_EVNT_CREGISTER:{
            buffer+="Se ha registrado un nuevo cliente en el dominio;";
            break;
        }
        
         case LOG_QUEUE_ERR_UNPACKER_QSP:{
            buffer+="Error, el programa ha fallado al crear la cola de mensajes para "
                    "el (Servidor de Quimera), verifique si se ha ejecutado con privilegios de root;";
            break;
        }
        
        case LOG_QUEUE_EVNT_OUT_INVESTMENT:{
            buffer+="Se ha enviado un mensaje de investidura;";
            break;
        }
        
        case LOG_QUEUE_EVNT_OUT_INVESTMENT_C:{
            buffer+="Se ha enviado una confirmación de mensaje de investidura;";
            break;
        }
        
        case LOG_QUEUE_EVNT_CLOGOUT:{
            buffer+="Error, se ha perdido la conexión con este cliente debido a expiración "
                    "del tiempo de espera;";
            break;
        }
        case LOG_QUEUE_ERR_SKILLER:{
            buffer+="Error, el programa ha fallado al iniciar el proceso (Serial killer);";
            break;
        
        }
        case LOG_QUEUE_EVNT_OUT_GUARD:{
            buffer+="Se ha enviado un mensaje de (Reporte de guarda);";
            break;
        }
        case LOG_QUEUE_EVNT_OUT_MISSING:{
            buffer+="Se ha enviado un mensaje de (Reporte de desaparecido);";
            break;
        }
        
        case LOG_QUEUE_EVNT_OUT_GUARD_C:{
            buffer+="Se ha enviado una confirmación de un mensaje de (Reporte de guarda);";
            break;
        }
        
        case LOG_QUEUE_EVNT_OUT_MISSING_C:{
            buffer+="Se ha enviado una confirmación de un mensaje de (Reporte de desaparecido);";
            break;
        }
        
        case LOG_QUEUE_EVNT_OUT_ADOPTION_P:{
            buffer+="Se ha enviado un mensaje de (Papeles de adopción);";
            break;
        }
        case LOG_QUEUE_ERR_IN_REPLY:{
            buffer+="Este mensaje ha sido replicado;";
            break;
        
        }
        case LOG_QUEUE_EVNT_EXPIRE:{
            buffer+="Ha caducado el tiempo de vida para este mensaje;";
            break;
            
        }
        
     case LOG_QUEUE_EVNT_CLEAR:{
            buffer+="Se ha iniciado el proceso de limpieza;";
            interrupt=true;
            break;
       
        }
        case LOG_QUEUE_ERR_CKILLER:{
            buffer+="Error, el programa ha fallado al iniciar el proceso (Complaint killer);";
            break;
        }
   
    }
    System_interface(time,"date +%c", sizeof(time));
    buffer+=time;
    buffer+="\n";
    file.write(buffer.c_str(),buffer.size());
    file.close();
}

void Logi (std::ofstream &file,const int &id,  std::string &buffer, Message_queue &mq, int &entry){
    
    buffer="";
    std::ostringstream ss;
    ss << entry;
    ss << ";";
    ss << id;
    buffer+=ss.str();
    buffer+=";";
    Concact(mq, buffer);
    buffer+="\n";
    file.write(buffer.c_str(),buffer.size());
    file.close();
}
int main (int argc, char** argv){
    
    std::ofstream loge;
    std::ofstream logi;
    std::string buffer;
    std::string loge_path=argv[2];
    std::string logi_path=argv[3];
    
    int entry_n=0;
    
    Message_queue message;
    
    int log_queue_id;
    log_queue_id=Message_queue_setup(LOGGER_QUEUE_KEY);
    
    if (log_queue_id==EXIT_FAILURE){ 
       loge.open(loge_path.c_str(),std::ofstream::out | std::ofstream::app);
       logi.open(logi_path.c_str(),std::ofstream::out | std::ofstream::app);
       Loge(loge,LOG_QUEUE_ERR_LOG,buffer,entry_n);
       return(EXIT_FAILURE);
    }
    
    
   while(!interrupt){
        if(msgrcv(log_queue_id,(struct msgbuf *)&message,sizeof(message)-sizeof(long),0,0)>0){
          
               
                entry_n+=1;
                loge.open(loge_path.c_str(),std::ofstream::out | std::ofstream::app);
                if(int(message.id_message)<100)
                        Loge(loge,message.id_message,buffer,entry_n);   
        
                else{
                        logi.open(logi_path.c_str(),std::ofstream::out | std::ofstream::app);
                        Loge(loge,message.id_message,buffer,entry_n);
                        Logi(logi,message.id_message,buffer,message,entry_n);
                }
                usleep(100000);        
        }
      
   }
    
    msgctl (log_queue_id, IPC_RMID, (struct msqid_ds *)NULL);
    return(EXIT_FAILURE);
}

